package com.horse.pack.common.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.compiler.JavaSourceCompiler;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * @author yangliu
 * @date 2024/12/13 10:57
 */
public class BeanCommonUtils {

    /**
     * 动态加载Java代码 类动态加属性
     * 只支持 String Integer Long Double LocalDate LocalDateTime
     *
     * @param packagePath 包路径
     * @param className   类名
     * @param addFiledMap
     */
    public static void loadClassFile(Map<String, Object> addFiledMap, String packagePath, String className) {
        // 将输入的Java代码写入到一个临时文件中
        //File javaFile = new File("/.../DynamicClass.java");
        // 输入的Java代码
        String inputCode = "package " + packagePath + ";\n" +
                "import java.time.LocalDateTime; \n" +
                "import java.time.LocalDate; \n" +
                "public class " + className + " {\n" +
                //"    }\n" +
                "{} \n" +
                "    public void execute() {\n" +
                "        System.out.println(\"动态编译代码片段成功执行\");\n" +
                "     }\n" +

                "}";

        String fieldString = "private String ${field};\n" +
                "\n" +
                "    public String get${CapitalCase}() {\n" +
                "        return ${field};\n" +
                "    }\n" +
                "\n" +
                "    public void set${CapitalCase}(String ${field}) {\n" +
                "        this.${field} = ${field};\n" +
                "    }\n";

        String fieldInteger = "private Integer ${field};\n" +
                "\n" +
                "    public Integer get${CapitalCase}() {\n" +
                "        return ${field};\n" +
                "    }\n" +
                "\n" +
                "    public void set${CapitalCase}(Integer ${field}) {\n" +
                "        this.${field} = ${field};\n" +
                "    }\n";

        String fieldLong = "private Long ${field};\n" +
                "\n" +
                "    public Long get${CapitalCase}() {\n" +
                "        return ${field};\n" +
                "    }\n" +
                "\n" +
                "    public void set${CapitalCase}(Long ${field}) {\n" +
                "        this.${field} = ${field};\n" +
                "    }\n";

        String fieldDouble = "private Double ${field};\n" +
                "\n" +
                "    public Double get${CapitalCase}() {\n" +
                "        return ${field};\n" +
                "    }\n" +
                "\n" +
                "    public void set${CapitalCase}(Double ${field}) {\n" +
                "        this.${field} = ${field};\n" +
                "    }\n";

        String fieldLocalDateTime = "private LocalDateTime ${field};\n" +
                "\n" +
                "    public LocalDateTime get${CapitalCase}() {\n" +
                "        return ${field};\n" +
                "    }\n" +
                "\n" +
                "    public void set${CapitalCase}(LocalDateTime ${field}) {\n" +
                "        this.${field} = ${field};\n" +
                "    }\n";

        String fieldLocalDate = "private LocalDate ${field};\n" +
                "\n" +
                "    public LocalDate get${CapitalCase}() {\n" +
                "        return ${field};\n" +
                "    }\n" +
                "\n" +
                "    public void set${CapitalCase}(LocalDate ${field}) {\n" +
                "        this.${field} = ${field};\n" +
                "    }\n";

        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, Object> entry : addFiledMap.entrySet()) {
            String key = entry.getKey();
            String r1 = null;
            if (entry.getValue() instanceof String) {
                r1 = StringUtils.replace(fieldString, "${field}", key);
            }
            if (entry.getValue() instanceof Integer) {
                r1 = StringUtils.replace(fieldInteger, "${field}", key);
            }
            if (entry.getValue() instanceof Long) {
                r1 = StringUtils.replace(fieldLong, "${field}", key);
            }
            if (entry.getValue() instanceof Double) {
                r1 = StringUtils.replace(fieldDouble, "${field}", key);
            }
            if (entry.getValue() instanceof LocalDateTime) {
                r1 = StringUtils.replace(fieldLocalDateTime, "${field}", key);
            }
            if (entry.getValue() instanceof LocalDate) {
                r1 = StringUtils.replace(fieldLocalDate, "${field}", key);
            }
            // 第二次替换
            String r2 = StringUtils.replace(r1, "${CapitalCase}", StringUtils.capitalize(key));
            stringBuilder.append(r2);
        }
        inputCode = StringUtils.replace(inputCode, "{}", stringBuilder.toString());
        JavaSourceCompiler javaSourceCompiler = JavaSourceCompiler.create(ClassLoader.getSystemClassLoader());
        javaSourceCompiler.addSource(packagePath + "." + className, inputCode);
        ClassLoader dynamicClass = javaSourceCompiler.compile();

        try {
            Class<?> dynamicClazz = dynamicClass.loadClass(packagePath + "." + className);
            Object dynamicObject = dynamicClazz.newInstance();
            for (Map.Entry<String, Object> entry : addFiledMap.entrySet()) {
                BeanUtil.setFieldValue(dynamicObject, entry.getKey(), entry.getValue());
            }
            System.out.println(JSON.toJSONString(dynamicObject));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
